﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace ForguncySecurityProviderCreator;

public static class SpCreator
{
    private static readonly string TemplateName = "ForguncyTemplate";
    private static readonly string AssemblyPath = "%AssemblyPath%";
    private static readonly string SpName = "%SpName%";
    private static readonly string ProjectPath = "%ProjectPath%";
    private static readonly string PackageToolsPath = "PackageTools";
    private static readonly string SecurityProviderSymbol = "SecurityProvider";

    public static async Task CreateSpByTemplateAsync(SpCreatorViewModel viewModel)
    {
        var templatePath = Path.GetFullPath(Path.Combine("..", "ForguncyTemplateSecurityProvider"));
        viewModel.SpProjectPath = Path.GetFullPath(viewModel.SpProjectPath);
        EnsureFolder(viewModel.SpProjectPath);
        var templateFiles = Directory.GetFiles(templatePath, "*.*", SearchOption.AllDirectories);

        foreach (var file in templateFiles)
        {
            var relativePath = EnsureCustomFileName(
                Path.GetDirectoryName(file)!.Replace(templatePath, "").TrimStart('\\'),
                viewModel);
            var sourceContent = await File.ReadAllTextAsync(file);
            var targetFileName = EnsureCustomFileName(Path.GetFileName(file), viewModel);
            string replacedContent;

            if (file.EndsWith(".json"))
            {
                // DependenceVersion.json
                replacedContent = EnsureDependenceVersion(sourceContent, viewModel);
            }
            else if (file.EndsWith(".cs"))
            {
                // ForguncyTemplateSecurityProvider.cs
                replacedContent = EnsureClassContent(sourceContent, viewModel);
            }
            else if (file.EndsWith(".csproj"))
            {
                // ForguncyTemplateSecurityProvider.csproj
                replacedContent = EnsureProjectContent(sourceContent, viewModel);
            }
            else if (file.EndsWith(".sln"))
            {
                // ForguncyTemplateSecurityProvider.sln
                replacedContent = EnsureClassContent(sourceContent, viewModel);
            }
            else if (file.EndsWith(".txt"))
            {
                // LICENSE.txt
                replacedContent = sourceContent;
            }
            else
            {
                // 其他文件无需拷贝
                continue;
            }

            var targetFolderPath = Path.Combine(viewModel.SpProjectPath, relativePath);
            EnsureFolder(targetFolderPath);
            var targetFilePath = Path.Combine(targetFolderPath, targetFileName);
            await using var fs = File.Open(targetFilePath, FileMode.CreateNew, FileAccess.ReadWrite,
                FileShare.None);
            // 写入文件的操作
            var byteArr = Encoding.UTF8.GetBytes(replacedContent);
            await fs.WriteAsync(byteArr, 0, byteArr.Length);
        }

        CopyPackageTools(viewModel);
    }

    private static void EnsureFolder(string path)
    {
        if (Directory.Exists(path) == false)
        {
            Directory.CreateDirectory(path!);
        }
    }

    private static string EnsureCustomFileName(string sourceFileName, SpCreatorViewModel viewModel)
    {
        if (!sourceFileName.StartsWith(TemplateName))
        {
            return sourceFileName;
        }

        return sourceFileName.Replace(TemplateName, viewModel.Name);
    }

    private static string EnsureDependenceVersion(string sourceContent, SpCreatorViewModel viewModel)
    {
        var model = JsonConvert.DeserializeObject<DependenceVersionModel>(sourceContent);
        model.DependenceVersion = viewModel.ForguncyVersion.ToString();
        return JsonConvert.SerializeObject(model);
    }

    private static string EnsureClassContent(string sourceContent, SpCreatorViewModel viewModel)
    {
        // 替换 namespace 以及 class name
        return sourceContent.Replace(TemplateName, viewModel.Name);
    }

    private static string EnsureProjectContent(string sourceContent, SpCreatorViewModel viewModel)
    {
        // 替换 %AssemblyPath%
        // 对应的文件在 forguncyWebsitePath\bin\ 目录下
        var assemblyFilePath = Path.Combine(viewModel.ForguncyWebsitePath, "bin");
        sourceContent = sourceContent.Replace(AssemblyPath, assemblyFilePath);

        // 替换 %ProjectPath%
        sourceContent = sourceContent.Replace(ProjectPath, viewModel.SpProjectPath.TrimEnd('\\'));

        // 替换 %SpName%
        return sourceContent.Replace(SpName, viewModel.Name + SecurityProviderSymbol);
    }

    private static void CopyPackageTools(SpCreatorViewModel viewModel)
    {
        // 创建 PackageTools 文件夹
        var packageToolsPath = Path.Combine(viewModel.SpProjectPath, PackageToolsPath);
        EnsureFolder(packageToolsPath);

        // 拷贝所有的PackageTools程序
        var fileNames = new List<string>()
        {
            "ForguncySecurityProviderPackageTool.deps.json",
            "ForguncySecurityProviderPackageTool.dll",
            "ForguncySecurityProviderPackageTool.exe",
            "ForguncySecurityProviderPackageTool.pdb",
            "ForguncySecurityProviderPackageTool.runtimeconfig.json"
        };

        fileNames.Where(File.Exists).ToList().ForEach(p =>
            File.Copy(
                Path.Combine(Directory.GetCurrentDirectory(), p),
                Path.Combine(packageToolsPath, p)));
    }
}